package com.zb.controller;

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Map.Entry;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.StringRequestEntity;

import com.zb.utils.MD5Util;
import com.zb.utils.WXUtil;

/**
 * 查询退款订单信息
 * 
 * 作者: zhoubang 
 * 日期：2015年10月29日 下午1:50:35
 */
public class RefundQuery {
    
    /**
     * 查询退款订单所需参数
     */
    private final static String appid = "";//公众号APPID
    private final static String mch_id = "";//公众号对应的商户号
    private static String key = "";//支付密钥，商户平台获取
    private final static String transaction_id = ""; //微信生成的订单号，在支付通知中有返回
    
    /**
     * 这里直接是main方法，业务实现逻辑你们自行复制到你们的项目系统中.
     * 
     * 其实实现方式与支付的思想是一样，很多方法都是通用的，比如生成签名、对参数进行生成xml格式字符串等.
     * 
     * 作者: zhoubang 
     * 日期：2015年10月29日 下午1:50:54
     * @param args
     */
    public static void main(String[] args) {
        
        SortedMap<Object, Object> parameters = new TreeMap<Object, Object>();
        parameters.put("appid", appid); //appid
        parameters.put("mch_id", mch_id); //微信商户号
        parameters.put("nonce_str", WXUtil.getNonceStr()); //随机字符串
        
        /**
         * 这里有4种选择，依次是：
         * transaction_id：微信订单号
         * out_trade_no：商户订单号，商户系统内部的订单号
         * out_refund_no：商户退款单号，商户侧传给微信的退款单号
         * refund_id：微信退款单号，微信生成的退款单号，在申请退款接口有返回
         * 
         * 推荐优先使用transaction_id，只要填写其中一个作为参数即可。至于值如何获取，我想，在你们支付之后，这些订单信息已经有了。
         */
        parameters.put("transaction_id", transaction_id); //微信订单号
        
        //创建签名，算法与支付的算法一样
        String sign = createSign("UTF-8", parameters);
        parameters.put("sign", sign);
        
        //生成请求报文
        String requestXML = getRequestXml(parameters);
        
        HttpClient client = new HttpClient();
        PostMethod myPost = new PostMethod("https://api.mch.weixin.qq.com/pay/refundquery");//退款查询接口
        client.getParams().setSoTimeout(300 * 1000);
        String result = null;
        try {
            myPost.setRequestEntity(new StringRequestEntity(requestXML, "text/xml", "utf-8"));
            int statusCode = client.executeMethod(myPost);
            if (statusCode == HttpStatus.SC_OK) {
                BufferedInputStream bis = new BufferedInputStream(myPost.getResponseBodyAsStream());
                byte[] bytes = new byte[1024];
                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                int count = 0;
                while ((count = bis.read(bytes)) != -1) {
                    bos.write(bytes, 0, count);
                }
                byte[] strByte = bos.toByteArray();
                result = new String(strByte, 0, strByte.length, "utf-8");
                bos.close();
                bis.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        //输出微信返回的退款信息详情
        System.out.println(result);
        
        //下面可以处理其他的业务...
        
    }

    /**
     * 生成查询退款订单信息的请求报文
     * 
     * 作者: zhoubang 
     * 日期：2015年10月29日 下午1:57:11
     * @param parameters
     * @return
     */
    public static String getRequestXml(SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        sb.append("<xml>");
        Set<Entry<Object, Object>> es = parameters.entrySet();
        Iterator<Entry<Object, Object>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) it.next();
            String k = (String) entry.getKey();
            String v = entry.getValue() + "";
            if ("attach".equalsIgnoreCase(k) || "body".equalsIgnoreCase(k) || "sign".equalsIgnoreCase(k)) {
                sb.append("<" + k + ">" + "<![CDATA[" + v + "]]></" + k + ">");
            } else {
                sb.append("<" + k + ">" + v + "</" + k + ">");
            }
        }
        sb.append("</xml>");
        return sb.toString();
    }
    
    /**
     * 生成签名
     * 
     * 作者: zhoubang 
     * 日期：2015年10月29日 下午1:57:05
     * @param characterEncoding
     * @param parameters
     * @return
     */
    public static String createSign(String characterEncoding, SortedMap<Object, Object> parameters) {
        StringBuffer sb = new StringBuffer();
        Set<Entry<Object, Object>> es = parameters.entrySet();
        Iterator<Entry<Object, Object>> it = es.iterator();
        while (it.hasNext()) {
            Map.Entry<Object, Object> entry = (Map.Entry<Object, Object>) it.next();
            String k = (String) entry.getKey();
            Object v = entry.getValue();
            /** 如果参数为key或者sign，则不参与加密签名 */
            if (null != v && !"".equals(v) && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }
        /** 支付密钥必须参与加密，放在字符串最后面 */
        sb.append("key=" + key);
        /** 记得最后一定要转换为大写 */
        String sign = MD5Util.MD5Encode(sb.toString(), characterEncoding).toUpperCase();
        return sign;
    }
}

